﻿#region Namespace Imports

using System;
using System.Collections.Generic;
using System.IO;
using GeoAPI.Coordinates;
using GeoAPI.Geometries;
using NPack.Interfaces;

#endregion

namespace GeoAPI.IO.WellKnownBinary
{
    public class WkbReader<TCoordinate> : IWkbReader<TCoordinate>
        where TCoordinate : ICoordinate<TCoordinate>, IEquatable<TCoordinate>,
                            IComparable<TCoordinate>, IConvertible,
                            IComputable<Double, TCoordinate>
    {
        public static IGeometry<TCoordinate> ToGeometry(Byte[] wkbData, IGeometryFactory<TCoordinate> geoFactory)
        {
            return GeometryFromWkb.Parse(wkbData, geoFactory);
        }

        public static IGeometry<TCoordinate> ToGeometry(Stream wkbData, IGeometryFactory<TCoordinate> geoFactory)
        {
            return GeometryFromWkb.Parse(wkbData, geoFactory);
        }

        public static IGeometry<TCoordinate> ToGeometry(BinaryReader wkbData, IGeometryFactory<TCoordinate> geoFactory)
        {
            return GeometryFromWkb.Parse(wkbData, geoFactory);
        }

        private IGeometryFactory<TCoordinate> _geoFactory;

        public WkbReader(IGeometryFactory<TCoordinate> geoFactory)
        {
            _geoFactory = geoFactory;
        }

        #region IWkbDecoder Members

        public IGeometryFactory<TCoordinate> GeometryFactory
        {
            set { _geoFactory = value; }
        }

        public IGeometry<TCoordinate> Read(Byte[] wkb)
        {
            return ToGeometry(wkb, _geoFactory);
        }

        public IGeometry<TCoordinate> Read(Byte[] wkb, Int32 offset)
        {
            Int32 inputLength = wkb.Length - offset;
            Byte[] wkbOffset = new Byte[inputLength];
            Buffer.BlockCopy(wkb, offset, wkbOffset, 0, inputLength);

            return ToGeometry(wkbOffset, _geoFactory);
        }

        public IGeometry<TCoordinate> Read(IEnumerable<Byte> wkb)
        {
            throw new NotImplementedException();
        }

        public IGeometry<TCoordinate> Read(Stream wkb)
        {
            return ToGeometry(wkb, _geoFactory);
        }

        public IGeometry<TCoordinate> Read(BinaryReader wkb)
        {
            return ToGeometry(wkb, _geoFactory);
        }

        public IEnumerable<IGeometry<TCoordinate>> ReadAll(Byte[] wkb)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<IGeometry<TCoordinate>> ReadAll(Byte[] wkb, Int32 offset)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<IGeometry<TCoordinate>> ReadAll(IEnumerable<Byte> wkb)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<IGeometry<TCoordinate>> ReadAll(BinaryReader wkbData)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IWkbReader Members

        IGeometryFactory IWkbReader.GeometryFactory
        {
            set
            {
                if (value is IGeometryFactory<TCoordinate>)
                    GeometryFactory = value as IGeometryFactory<TCoordinate>;
                throw new ArgumentException();
            }
        }

        IGeometry IWkbReader.Read(byte[] wkb)
        {
            return Read(wkb);
        }

        IGeometry IWkbReader.Read(byte[] wkb, int offset)
        {
            return Read(wkb, offset);
        }

        IGeometry IWkbReader.Read(IEnumerable<byte> wkb)
        {
            return Read(wkb);
        }

        IGeometry IWkbReader.Read(Stream wkbData)
        {
            return Read(wkbData);
        }

        IGeometry IWkbReader.Read(BinaryReader wkbData)
        {
            return Read(wkbData);
        }

        IEnumerable<IGeometry> IWkbReader.ReadAll(byte[] wkb)
        {
            foreach (IGeometry<TCoordinate> geometry in this.ReadAll(wkb))
            {
                yield return geometry;
            }
        }

        IEnumerable<IGeometry> IWkbReader.ReadAll(byte[] wkb, int offset)
        {
            foreach (IGeometry<TCoordinate> geometry in this.ReadAll(wkb,offset))
            {
                yield return geometry;
            }
        }

        IEnumerable<IGeometry> IWkbReader.ReadAll(IEnumerable<byte> wkb)
        {
            foreach (IGeometry<TCoordinate> geometry in this.ReadAll(wkb))
            {
                yield return geometry;
            }
        }

        IEnumerable<IGeometry> IWkbReader.ReadAll(BinaryReader wkbData)
        {
            foreach (IGeometry<TCoordinate> geometry in this.ReadAll(wkbData))
            {
                yield return geometry;
            }
        }

        #endregion
    }
}